/**
 * @Author yang
 * @Description json 化时间格式自定义
 * @Date 2021/2/26
 * @Time 9:20
 **/
package elastic

import (
	"errors"
	"regexp"
	"strings"
	"time"
)

const (
	DateTime = "2006-01-02  15:04:05"
	Date     = "2006-01-02"
	Date1    = "2006/01/02"
	Time     = "15:04:05"

	ZhDate        = "2006年01月02日"
	ZhDateTime    = "2006年01月02日  15:04:05"
	ZhAllDateTime = "2006年01月02日  15时04分05秒"
	ZhTime        = "15时04分05秒"

	SYSTEM_DEFAULT_TIME = time.RFC3339Nano
)

type FormateType string

// define costome time format by delare a new type, then add a  dalare case
type MVTime mvTime

// 自定义格式化类型
func (this *MVTime) Type(formatType FormateType) {
	this.format = string(formatType)
	return
}

func NewMVTime(timePoint time.Time) MVTime {
	mTime := mvTime{timeval: timePoint, format: SYSTEM_DEFAULT_TIME}
	return MVTime(mTime)
}

func NewMVTimeWithFomat(timePoint time.Time, formatType FormateType) MVTime {
	mTime := mvTime{timeval: timePoint, format: string(formatType)}
	return MVTime(mTime)
}

func Formate(formateType interface{}) string {
	if formateType != nil {
		return formateType.(MVTime).format
	}
	return SYSTEM_DEFAULT_TIME
}

// =====================实现部分=======================

type mvTime struct {
	timeval time.Time // 时间
	format  string    // json 化格式
}

// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t MVTime) MarshalJSON() ([]byte, error) {
	if y := time.Time(t.timeval).Year(); y < 0 || y >= 10000 {
		// RFC 3339 is clear that years are 4 digits exactly.
		// See golang.org/issue/4556#c15 for more discussion.
		return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
	}

	b := make([]byte, 0, len(Formate(t))+2)
	b = append(b, '"')
	b = time.Time(t.timeval).AppendFormat(b, Formate(t))
	b = append(b, '"')
	return b, nil
}

// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
func (t *MVTime) UnmarshalJSON(data []byte) error {
	// Ignore null, like in the main JSON package.
	if string(data) == "null" {
		return nil
	}
	// Fractional seconds are handled implicitly by Parse.
	var err error
	timePoint, err := time.Parse(autoRecognizeFomate(string(data)), string(data))
	*t = NewMVTime(timePoint)
	return err
}

var timeReplaceEles = []string{"2006", "01", "02", "15", "04", "05"}

func autoRecognizeFomate(timeStr string) (res string) {
	compileStr, _ := regexp.Compile("\\d+")
	submatch := compileStr.FindAllStringSubmatch(timeStr, -1)
	replaceCount := 0
	switch len(submatch) {
	case 6:
		res = compileStr.ReplaceAllStringFunc(timeStr, func(timeStr string) (res string) {
			res = timeReplaceEles[replaceCount]
			replaceCount += 1
			//fmt.Println("=====> ", timeStr, replaceCount)
			return
		})
	case 5:
		fallthrough
	case 4:
		res = compileStr.ReplaceAllStringFunc(timeStr, func(timeStr string) (res string) {
			// 未带年份
			if replaceCount == 0 && len(timeStr) < 4 {
				replaceCount += 1
			}
			res = timeReplaceEles[replaceCount]
			replaceCount += 1
			//fmt.Println("=====> ", timeStr, replaceCount)
			return
		})
	case 3:
		res = compileStr.ReplaceAllStringFunc(timeStr, func(timeStr string) (res string) {
			// 未带年份
			if replaceCount == 0 && len(timeStr) < 4 {
				replaceCount += 3
			}
			res = timeReplaceEles[replaceCount]
			replaceCount += 1
			//fmt.Println("=====> ", timeStr, replaceCount)
			return
		})

	case 2:
		res = compileStr.ReplaceAllStringFunc(timeStr, func(timeStr string) (res string) {
			// 未带年份
			if replaceCount == 0 &&
				(strings.Contains(timeStr, ":") ||
					strings.Contains(timeStr, "时") ||
					strings.Contains(timeStr, "分")) {
				replaceCount += 3
			} else if replaceCount == 0 && len(timeStr) < 4 {
				replaceCount += 1
			}
			res = timeReplaceEles[replaceCount]
			replaceCount += 1
			//fmt.Println("=====> ", timeStr, replaceCount)
			return
		})

	}
	res = strings.TrimSpace(res)
	return
}
